package gins

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/mars/pkg/errors"
	"github.com/mars/pkg/loggers"
)

var (
	// handleErrorHooks dosen't guarantee thread-safely
	handleErrorHooks []func(*gin.Context, error)
)

type (
	// HandleErrorFunc will return an error after completes a request, and the returned results will be processed by the
	// HandleErrorWrapper method.
	HandleErrorFunc func(*gin.Context) error

	// HandleRestFunc will return a response body or an error after completes a request,
	// and the returned results will be processed by HandleRestWrapper method.
	HandleRestFunc func(*gin.Context) (interface{}, error)

	// HandlePageRestFunc return a response body and total count of records or return a err
	HandlePageRestFunc func(*gin.Context) (interface{}, int64, error)

	// HanlderRawResponseFunc will return a raw response body or an error after completes a request,
	// and the returned results will be processed by HandleRawResponseWrapper method.
	HanlderRawResponseFunc func(*gin.Context) (*Response, error)
)

func HandleRawResponseWrapper(fn HanlderRawResponseFunc) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var (
			resp *Response
			err  error
		)

		if resp, err = fn(ctx); err == nil {
			ctx.JSON(resp.Code, resp)
			return
		}

		loggers.Errorf("%#+v", err)
		be, ok := err.(*errors.BusinessError)
		if !ok {
			be = errors.New(http.StatusInternalServerError, "服务器内部错误")
		}
		ctx.JSON(be.HTTPStatus, Response{
			Code:    be.Code,
			Message: be.Message,
		})
	}
}
func HandleErrorWrapper(fn HandleErrorFunc) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var err error
		if err = fn(ctx); err == nil {
			ctx.Status(http.StatusOK)
			return
		}

		loggers.Errorf("%#+v", err)
		be, ok := err.(*errors.BusinessError)
		if !ok {
			be = errors.New(http.StatusInternalServerError, "服务器内部错误")
		}

		ctx.JSON(be.HTTPStatus, Response{
			Code:    be.Code,
			Message: be.Message,
		})
	}
}

func HandleRestWrapper(fn HandleRestFunc) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var (
			body interface{}
			err  error
		)

		if body, err = fn(ctx); err == nil {
			ctx.JSON(http.StatusOK, Response{
				Code:    http.StatusOK,
				Message: "success",
				Data:    body,
			})
			return
		}

		loggers.Errorf("%#+v", err)
		be, ok := err.(*errors.BusinessError)
		if !ok {
			be = errors.New(http.StatusInternalServerError, "服务器内部错误")
		}
		ctx.JSON(be.HTTPStatus, Response{
			Code:    be.Code,
			Message: be.Message,
		})
	}
}

func HandlePageRestWrapper(fn HandlePageRestFunc) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var (
			resp Response = Response{
				Code: http.StatusOK,
			}
			err error
		)

		if resp.Data, resp.Total, err = fn(ctx); err == nil {
			ctx.JSON(http.StatusOK, &resp)
			return
		}

		loggers.Errorf("%#+v", err)
		be, ok := err.(*errors.BusinessError)
		if !ok {
			be = errors.New(http.StatusInternalServerError, "服务器内部错误")
		}
		ctx.JSON(be.HTTPStatus, Response{
			Code:    be.Code,
			Message: be.Message,
		})
	}
}

func RegisterHandlErrorHooks(hooks ...func(*gin.Context, error)) {
	if handleErrorHooks == nil {
		handleErrorHooks = make([]func(*gin.Context, error), 0, 1)
	}
	handleErrorHooks = append(handleErrorHooks, hooks...)
}
